//
// Created on 2025/6/25.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#include "SkOHImageCodec.h"
#include "codec/SkCodecAnimation.h"
#include "codec/SkEncodedImageFormat.h"
#include "include/core/SkStream.h"
#include "include/core/SkImage.h"
#include "src/image/SkImage_OH.h"
#include "src/codec/SkCodecPriv.h"

std::unique_ptr<SkCodec> SkOHImageCodec::makeFromData(sk_sp<SkData> data) {
    OH_ImageSourceNative *image_source = nullptr;
    OH_ImageSource_Info *info = nullptr;
    OH_ImageSourceInfo_Create(&info);
    if (info == nullptr) {
        return nullptr;
    }

    // The data will be coyied to ImageSourceNative.
    // No modifications will be made to origin data.
    auto err_code = OH_ImageSourceNative_CreateFromData((uint8_t *)data->bytes(), data->size(), &image_source);
    if (image_source == nullptr || err_code != IMAGE_SUCCESS) {
        return nullptr;
    }

    uint32_t width = 0, height = 0;
    OH_ImageSourceNative_GetImageInfo(image_source, 0, info);
    OH_ImageSourceInfo_GetWidth(info, &width);
    OH_ImageSourceInfo_GetHeight(info, &height);
    OH_ImageSourceInfo_Release(info);
    if (width == 0 || height == 0) {
        OH_ImageSourceNative_Release(image_source);
        return nullptr;
    }

    auto encode_info =
        SkEncodedInfo::Make(width, height, SkEncodedInfo::Color::kRGBA_Color, SkEncodedInfo::Alpha::kUnpremul_Alpha, 8);

    uint32_t frameCount = 1;
    OH_ImageSourceNative_GetFrameCount(image_source, &frameCount);
    int loopCnt = frameCount == 1 ? 0 : sk_codec_get_animation_loop_count(data);

    return std::unique_ptr<SkCodec>(new SkOHImageCodec(std::move(encode_info),
                                                       skcms_PixelFormat::skcms_PixelFormat_RGBA_8888, nullptr,
                                                       kTopLeft_SkEncodedOrigin, image_source, loopCnt));
}


SkOHImageCodec::SkOHImageCodec(SkEncodedInfo &&info, XformFormat srcFormat, std::unique_ptr<SkStream> stream,
                               SkEncodedOrigin origin, OH_ImageSourceNative *source, int loopCnt)
    : SkCodec(std::move(info), srcFormat, std::move(stream), origin), fSource(source), fRepetitionCount(loopCnt) {
    uint32_t frameCount = 1;
    OH_ImageSourceNative_GetFrameCount(fSource, &frameCount);
    int *timeList = new int[frameCount];
    OH_ImageSourceNative_GetDelayTimeList(fSource, timeList, frameCount);
    for (int i = 0; i < frameCount; i++) {
        fFrameInfo.push_back({kNoFrame, timeList[i], true, kUnpremul_SkAlphaType, false,
                              SkCodecAnimation::DisposalMethod::kKeep, SkCodecAnimation::Blend::kSrcOver,
                              this->bounds()});
    }
}

SkOHImageCodec::~SkOHImageCodec() {
    if (fSource) {
        OH_ImageSourceNative_Release(fSource);
    }
}


SkCodec::Result SkOHImageCodec::onGetPixels(const SkImageInfo& info,
                               void* pixels, size_t rowBytes, const Options& opts,
                               int* rowsDecoded) {
    auto [image, result] = onGetImage(info, &opts);
    if (result != SkCodec::Result::kSuccess) {
        return result;
    } else {
        int srcX = 0, srcY = 0;
        if (opts.fSubset) {
            srcX = opts.fSubset->fLeft;
            srcY = opts.fSubset->fTop;
        }
        if (image->readPixels(info, pixels, rowBytes, srcX, srcY)) {
            return SkCodec::Result::kSuccess;
        } else {
            return SkCodec::Result::kErrorInInput;
        }
    }
}
    
std::tuple<sk_sp<SkImage>, SkCodec::Result> SkOHImageCodec::onGetImage(const SkImageInfo& info,
                                                         const Options* opts) {
    int frameIndex = 0;
    if (opts) {
        frameIndex = opts->fFrameIndex;
    }
    
    auto image = sk_make_sp<SkImage_OH>(info, fSource, frameIndex, kNeedNewImageUniqueID, false);
    if (image->isValid(nullptr)) {
        return {image, SkCodec::Result::kSuccess};
    } else {
        return {nullptr, SkCodec::Result::kInvalidInput};
    }
}


int SkOHImageCodec::onGetFrameCount() {
        return fFrameInfo.size();
}

bool SkOHImageCodec::onGetFrameInfo(int frameIndex, FrameInfo *info) const {
    if (info && frameIndex >=0 && frameIndex < fFrameInfo.size()) {
        *info = fFrameInfo[frameIndex];
        return true;
    } else {
        return false;
    }
}

int SkOHImageCodec::onGetRepetitionCount() {
    return fRepetitionCount;
}

SkEncodedImageFormat SkOHImageCodec::onGetEncodedFormat() const {
    RENDER_UNIMPLEMENTED;
    return SkEncodedImageFormat::kJPEGXL;
}

int SkOHImageCodec::onOutputScanline(int inputScanline) const {
    RENDER_UNIMPLEMENTED;
    return 0;
}

bool SkOHImageCodec::conversionSupported(const SkImageInfo& dst, bool srcIsOpaque,
                                     bool needsColorXform) {
    if (dst.colorType() != kRGBA_8888_SkColorType) {
        return false;
    }
    return true;
}
